#include "bsp_usb.h"
#include <string.h>
#include "bsp_timer.h"

#define APP_ERR_TRAP(a)             ({if(a) {__asm("BKPT #0\n");}}) /* trap the error location */
#define READ_BUF_SIZE               (8U)
#define LINE_CODING_LENGTH          (0x07U)

static bool  b_usb_attach = false;
static unsigned char g_usb_configured = 0;
static unsigned char g_usb_dtr        = 0;
static unsigned char g_usb_rts        = 0;
usb_status_t usb_event;


void usb_cdc_init(void)
{
    fsp_err_t err=R_USB_Open(&g_basic0_ctrl, &g_basic0_cfg);
    assert(FSP_SUCCESS==err);

    while(!usb_cdc_handle());
}

static fsp_err_t check_for_write_complete(void)
{
    usb_status_t usb_write_event = USB_STATUS_NONE;
    int32_t timeout_count = UINT16_MAX;
    fsp_err_t err = FSP_SUCCESS;
    usb_event_info_t    event_info = {0};

    do
    {
        err = R_USB_EventGet (&event_info, &usb_write_event);

        if (FSP_SUCCESS != err)
        {
            return err;
        }

        --timeout_count;

        if (0 > timeout_count)
        {
            timeout_count = 0;
            err = (fsp_err_t)USB_STATUS_NONE;
            break;
        }
    }
    while(USB_STATUS_WRITE_COMPLETE != usb_write_event);

    return err;
}
fsp_err_t usb_cdc_write(uint8_t *p_data,uint32_t len)
{
    fsp_err_t err = FSP_SUCCESS;

    err = R_USB_Write (&g_basic0_ctrl, (uint8_t*)p_data, len, USB_CLASS_PCDC);

    /* Handle error */
    if (FSP_SUCCESS != err)
    {
        return err;
    }

    err = check_for_write_complete();

    if (FSP_SUCCESS != err)
    {
        /* Did not get the event hence returning error */
        return FSP_ERR_USB_FAILED;
    }

    return err;
}


uint32_t usb_cdc_handle(void)
{
    fsp_err_t err                           = FSP_SUCCESS;
    usb_event_info_t    event_info          = {0};
    uint8_t g_buf[READ_BUF_SIZE]            = {0};
    static usb_pcdc_linecoding_t g_line_coding;

    /* Obtain USB related events */
    err = R_USB_EventGet (&event_info, &usb_event);

    /* Handle error */
    if (FSP_SUCCESS != err)
    {
        APP_ERR_TRAP(err);
    }

    /* USB event received by R_USB_EventGet */
    switch (usb_event)
    {
        case USB_STATUS_CONFIGURED:
        {
            err = R_USB_Read (&g_basic0_ctrl, g_buf, READ_BUF_SIZE, USB_CLASS_PCDC);

            /* Handle error */
            if (FSP_SUCCESS != err)
            {
                APP_ERR_TRAP(err);
            }
            g_usb_configured=1;

            break;
        }

        case USB_STATUS_READ_COMPLETE:
        {
            if(b_usb_attach)
            {
                err = R_USB_Read (&g_basic0_ctrl, g_buf, READ_BUF_SIZE, USB_CLASS_PCDC);
            }

            /* Handle error */
            if (FSP_SUCCESS != err)
            {
                APP_ERR_TRAP(err);
            }

            break;
        }

        case USB_STATUS_REQUEST : /* Receive Class Request */
        {
            /* Check for the specific CDC class request IDs */
            if (USB_PCDC_SET_LINE_CODING == (event_info.setup.request_type & USB_BREQUEST))
            {
                err =  R_USB_PeriControlDataGet (&g_basic0_ctrl, (uint8_t *) &g_line_coding, LINE_CODING_LENGTH );

                /* Handle error */
                if (FSP_SUCCESS != err)
                {
                    APP_ERR_TRAP(err);
                }
            }
            else if (USB_PCDC_GET_LINE_CODING == (event_info.setup.request_type & USB_BREQUEST))
            {
                err =  R_USB_PeriControlDataSet (&g_basic0_ctrl, (uint8_t *) &g_line_coding, LINE_CODING_LENGTH );

                /* Handle error */
                if (FSP_SUCCESS != err)
                {
                    APP_ERR_TRAP(err);
                }
            }
            else if (USB_PCDC_SET_CONTROL_LINE_STATE == (event_info.setup.request_type & USB_BREQUEST))
            {
                err = R_USB_PeriControlStatusSet (&g_basic0_ctrl, USB_SETUP_STATUS_ACK);

                /* Handle error */
                if (FSP_SUCCESS != err)
                    //if (FSP_SUCCESS != g_err)
                {
                    APP_ERR_TRAP(err);
                }

                /* 2. 取出 DTR/RTS 位 */
               uint16_t control_line = event_info.setup.request_value;   /* wValue 低字节就是位图 */
               g_usb_dtr = (control_line & 0x01) ? 1 : 0;       /* 全局变量 */
               g_usb_rts = (control_line & 0x02) ? 1 : 0;
                //g_usb_dtr=1;
            }
            else
            {
                /* none */
            }

            break;
        }

        case USB_STATUS_DETACH:
        case USB_STATUS_SUSPEND:
        {
            b_usb_attach = false;
            memset (g_buf, 0, sizeof(g_buf));
            break;
        }

        case USB_STATUS_RESUME:
        {
            b_usb_attach = true;
            break;
        }

        default:
        {
            break;
        }
    }

    return (g_usb_configured&&g_usb_dtr);
}

void cdc_task(void)
{
    static uint32_t dwcdc_tick=0;
    if(GetSysTick()-dwcdc_tick>1000)
    {
        usb_cdc_write("cdc_test!\r\n",sizeof("cdc_test!\r\n")-1);

        dwcdc_tick=GetSysTick();
    }
}
